//
//  BYAiScanViewController.swift
//  BYScan
//
//  Created by yetupal on 2023/6/28.
//

import UIKit
import AVFoundation

import MLKitCommon
import MLKitVision
import MLKitBarcodeScanning


// AI扫码识别
class BYAkScanViewController: UIViewController {
    
    // MARK: - 页面控件
    lazy var containerLayer: UIView = {
        let iView = UIView()
        iView.backgroundColor = UIColor.black.withAlphaComponent(0.518)
        iView.isHidden = true
        return iView
    }()
    
    lazy var reminderLabel: UILabel = {
        let iView = UILabel()
        iView.font = UIFont.systemFont(ofSize: 12)
        iView.text = "轻触小绿点,选择识别位置"
        iView.textColor = .white
        iView.isHidden = true
        return iView
    }()
    

    lazy var backTapper: UIButton = {
        let iView = UIButton(type: .custom)
        iView.frame = CGRect(x: 0, y: 0, width: 54, height: 34)
        iView.setImage(bbModularImage("icon_navbar_back_white"), for: .normal)
        iView.contentHorizontalAlignment = .left
        iView.addTarget(self, action: #selector(onTouchCloseVC), for: .touchUpInside)
        return iView
    }()

    lazy var switchTapper: UISegmentedControl = {
        let iView = UISegmentedControl.init(items: ["二维码", "条形码"])
        iView.setTitleTextAttributes([.foregroundColor : UIColor.black, .font: UIFont.systemFont(ofSize: 16)], for: .selected)
        iView.setTitleTextAttributes([.foregroundColor : UIColor.white, .font: UIFont.systemFont(ofSize: 12)], for: .normal)
        iView.addTarget(self, action: #selector(onTouchChanage(segmented:)), for: .valueChanged)
        iView.layer.borderColor = UIColor.white.cgColor
        iView.layer.borderWidth = 1
        iView.isHidden = true
        if #available(iOS 13.0, *) {
            iView.selectedSegmentTintColor = UIColor.white.withAlphaComponent(0.618)
        } else {
            iView.tintColor = UIColor.black.withAlphaComponent(0.618)
        }
        
        iView.selectedSegmentIndex = 0
        return iView
    }()
    
    lazy var aaTapper: UIButton = {
        let iView = UIButton(type: .custom)
        iView.setImage(bbModularImage("icon_qcode_photo"), for: .normal)
        iView.addTarget(self, action: #selector(aaTouch(sender:)), for: .touchUpInside)
        return iView
    }()

    lazy var bbTapper: UIButton = {
        let iView = UIButton(type: .custom)
        iView.setImage(bbModularImage("icon_flashlight_ok"), for: .normal)
        iView.addTarget(self, action: #selector(bbTouch(sender:)), for: .touchUpInside)
        return iView
    }()
    
    lazy var stackView: UIStackView = {
        let iView = UIStackView()
        iView.axis = .horizontal
        iView.distribution = .fillEqually
        iView.spacing = 20
        return iView
    }()
    
    // 遮罩层
    private var scanMaskLayer: BYScanMaskView?
    
    // 导航尺寸
    private var kNavboxSize: CGSize = CGSize(width: 158, height: 34)
    
    // 结果渲染
    var completionTrigger: ((String) -> Void)?
    
    // 标记颜色
    private let markThemeColor = UIColor(red: CGFloat(54/255.0), green: CGFloat(171/255.0), blue: CGFloat(96/255.0), alpha: 1.0)
    // MARK: - 页面数据
    
    // 检测结果
    private var outcomeWidget: [UIButton] = []
    private var outcomeValues: [BYAiScanData] = []
    
    // 扫描器
    private var barcodeOptions = BarcodeScannerOptions(formats: .all)
    private var barcodeScanner = BarcodeScanner.barcodeScanner()
    
    // MARK: - 采集数据
    private var captureSession: AVCaptureSession?
    private var captureDevice: AVCaptureDevice?
    private var input: AVCaptureDeviceInput?
    // 输出视频流
    private var videoOutput: AVCaptureVideoDataOutput?
    private var videoPreviewLayer: AVCaptureVideoPreviewLayer?
    
    // 识别枷锁
    private var isLockValue: Bool = false
    
    // 是否重新加载配置
    private var isReloadConfigValue = true

    override func viewDidLoad() {
        super.viewDidLoad()
        self.title = "扫一扫"
        self.navigationItem.titleView = self.switchTapper
        self.navigationController?.navigationBar.night_black()
        self.navigationItem.leftBarButtonItem = UIBarButtonItem(customView: backTapper)
        self.view.backgroundColor = UIColor.black
//        edgesForExtendedLayout = UIRectEdge(rawValue: 0)
        // Do any additional setup after loading the view.
        
        self.view.addSubview(self.containerLayer)
        self.view.addSubview(self.reminderLabel)

        self.containerLayer.translatesAutoresizingMaskIntoConstraints = false
        self.containerLayer.leftAnchor.constraint(equalTo: self.view.leftAnchor).isActive = true
        self.containerLayer.rightAnchor.constraint(equalTo: self.view.rightAnchor).isActive = true
        self.containerLayer.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
        self.containerLayer.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
        
        self.reminderLabel.translatesAutoresizingMaskIntoConstraints = false
        self.reminderLabel.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
        let bfy: CGFloat = self.view.safeAreaInsets.bottom + 30
        self.reminderLabel.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: -bfy).isActive = true
    
        // 底部操作按钮
        self.view.addSubview(stackView)
        self.stackView.addArrangedSubview(aaTapper)
        self.stackView.addArrangedSubview(bbTapper)
        
        self.stackView.translatesAutoresizingMaskIntoConstraints = false
        self.stackView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
        self.stackView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: -(self.view.safeAreaInsets.bottom + 30)).isActive = true
        self.stackView.heightAnchor.constraint(equalToConstant: 72).isActive = true
        self.stackView.widthAnchor.constraint(equalToConstant: 280).isActive = true

        // 加载类型模式
        self.switchTapper.selectedSegmentIndex = BYScanStyle.defaultServie.isWhetherBarCode ? 1 : 0

        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now()) { [weak self] in
            guard let wkThis = self else { return }
            wkThis.askLoaderWidget()
            wkThis.askScanModeSwitching()
            wkThis.configureLoader()
            // 开始相机流
            wkThis.startTask()
        }
    }
    
    private func askLoaderWidget() -> Void {
        // 加载遮罩
        self.scanMaskLayer?.removeFromSuperview()
        self.scanMaskLayer = BYScanMaskView()
        self.scanMaskLayer?.frame = self.view.bounds
        self.view.addSubview(self.scanMaskLayer!)
        self.scanMaskLayer?.startScanAnimation()
        
        self.view.bringSubviewToFront(self.stackView)
    }
    
    // 扫码模式切换  true 条形码 false 二维码
    private func askScanModeSwitching() {
        print("重新加载")
        if !BYScanStyle.defaultServie.isWhetherBarCode {
            self.barcodeOptions = BarcodeScannerOptions(formats: BarcodeFormat.qrCode)
        } else {
            self.barcodeOptions = BarcodeScannerOptions(formats: BarcodeFormat(rawValue: BarcodeFormat.code128.rawValue
                                                                     | BarcodeFormat.code39.rawValue
                                                                     | BarcodeFormat.code93.rawValue
                                                                     | BarcodeFormat.codaBar.rawValue
                                                                     | BarcodeFormat.dataMatrix.rawValue
                                                                     | BarcodeFormat.EAN13.rawValue
                                                                     | BarcodeFormat.EAN8.rawValue
                                                                     | BarcodeFormat.ITF.rawValue
                                                                     | BarcodeFormat.UPCA.rawValue
                                                                     | BarcodeFormat.UPCE.rawValue
                                                                     | BarcodeFormat.PDF417.rawValue
                                                                     | BarcodeFormat.aztec.rawValue))
        }
        // 刷新
        self.isReloadConfigValue = true
    }
    
    

    // 页面关闭
    @objc func onTouchCloseVC() {
        self.dismiss(animated: true)
    }
    
    
    @objc func aaTouch(sender: UIButton) {
        BYPermissions.authorizePhotoWith { [weak self] _ in
            let picker = UIImagePickerController()
            picker.sourceType = UIImagePickerController.SourceType.photoLibrary
            picker.delegate = self
            picker.allowsEditing = true
            self?.present(picker, animated: true, completion: nil)
        }
    }
    
    
    // 手电筒
    @objc func bbTouch(sender: UIButton) {

        guard let deviceTemp = input?.device else { return }
        guard captureDevice != nil && captureDevice!.hasFlash && captureDevice!.hasTorch else { return }
        
        do {
            try input?.device.lockForConfiguration()
            input?.device.torchMode = ( deviceTemp.torchMode == .off) ? AVCaptureDevice.TorchMode.on : AVCaptureDevice.TorchMode.off
            input?.device.unlockForConfiguration()
        } catch let error as NSError {
            print("device.lockForConfiguration(): \(error)")
        }
    }
    
    /*
     // MARK: - Navigation
     
     // In a storyboard-based application, you will often want to do a little preparation before navigation
     override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
     // Get the new view controller using segue.destination.
     // Pass the selected object to the new view controller.
     }
     */
    
    // 初始化配置信息
    private func configureLoader() -> Void {
        
        self.captureDevice = AVCaptureDevice.default(for: .video)
        
        guard let kk_captureDevice = self.captureDevice else { return }
        
        guard let deviceInput = try? AVCaptureDeviceInput(device: kk_captureDevice) else { return }
        
        self.input = deviceInput
        
        // 初始化captureSession对象，并在捕获会话上设置输入设备
        self.captureSession = AVCaptureSession()

        // 分辨率调整
        captureSession?.beginConfiguration()

        captureSession?.sessionPreset = AVCaptureSession.Preset.hd1280x720
        captureSession?.commitConfiguration()
    
        // 自动对焦
        if kk_captureDevice.isFocusPointOfInterestSupported && kk_captureDevice.isFocusModeSupported(.continuousAutoFocus) {
            try? deviceInput.device.lockForConfiguration()
            deviceInput.device.focusPointOfInterest = CGPoint.init(x: 0.5, y: 0.5)
            deviceInput.device.focusMode = AVCaptureDevice.FocusMode.continuousAutoFocus
            deviceInput.device.unlockForConfiguration()
        }
        captureSession?.addInput(deviceInput)
        
        // 视频流
        let captureMetadataOutput = AVCaptureVideoDataOutput()
        // 延迟帧直接丢弃
        captureMetadataOutput.alwaysDiscardsLateVideoFrames = true
        captureMetadataOutput.setSampleBufferDelegate(self, queue: DispatchQueue.main)
        captureMetadataOutput.videoSettings = [String(kCVPixelBufferPixelFormatTypeKey): kCVPixelFormatType_32BGRA]
        captureSession?.addOutput(captureMetadataOutput)
        self.videoOutput = captureMetadataOutput
        
        guard let kk_captureSession = self.captureSession else { return }
        
        videoPreviewLayer = AVCaptureVideoPreviewLayer(session: kk_captureSession)
        // 比例调整下
        videoPreviewLayer?.videoGravity = AVLayerVideoGravity.resize
        videoPreviewLayer?.frame = self.view.layer.bounds
        self.view.layer.addSublayer(videoPreviewLayer!)
        
        // 调整图层
        self.askLoaderWidget()
        
        // 遮罩置顶
        self.view.bringSubviewToFront(self.containerLayer)
        self.view.bringSubviewToFront(self.reminderLabel)
    }
    
    // 识别相册
    private func identifyAlbums(pic: UIImage?) -> Void {
        
        guard let rspImage = pic else { return }
        // 配置条形码扫描器
        let barcodeOptions = BarcodeScannerOptions(formats: .all)
        let visionImage = VisionImage(image: rspImage)
        
        let barcodeScanner = BarcodeScanner.barcodeScanner(options: barcodeOptions)
        barcodeScanner.process(visionImage) { [weak self] features, error in
            guard let wkThis = self else { return  }
            guard error == nil, let features = features, !features.isEmpty else { return }
            // 播放音乐
            DispatchQueue.main.async {    BYBundleSubject.playMusic() }
            // 识别第一个
            wkThis.completionTrigger?(features.first?.displayValue ?? "")
            DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.382) {
                if features.count == 1 {
                    wkThis.dismiss(animated: true)
                }
            }
        }
    }
    
    // MARK: - 事件处理
    @objc func onTouchChanage(segmented: UISegmentedControl) {
        BYScanStyle.defaultServie.isWhetherBarCode = segmented.selectedSegmentIndex != 0
        self.askLoaderWidget()
        self.askScanModeSwitching()
    }
    
    // 开始扫描
    private func startTask() -> Void {
        print("开始扫描")
        switch AVCaptureDevice.authorizationStatus(for: AVMediaType.video) {
        case .denied, .restricted:
            // 权限禁用
            break
        default:
            // 其他线程调用
            if let xx_captureSession = self.captureSession, xx_captureSession.isRunning { return }
            DispatchQueue.global().asyncAfter(deadline: DispatchTime.now()) { [weak self] in
                guard let wkThis = self else { return }
                wkThis.captureSession?.startRunning()
            }
            break
        }
    }
    
    private func stopTask() -> Void {
        print("停止识别功能")
        switch AVCaptureDevice.authorizationStatus(for: AVMediaType.video) {
        case .denied, .restricted:
            // 权限禁用
            break
        default:
            if let xx_captureSession = self.captureSession, !xx_captureSession.isRunning { return }
            DispatchQueue.main.async { [weak self] in
                guard let wkThis = self else { return }
                wkThis.captureSession?.stopRunning()
            }
            break
        }
        
    }
    
    // 屏幕旋转
    override func viewWillLayoutSubviews() {
        super.viewDidLayoutSubviews()
        
        videoPreviewLayer?.frame = self.view.layer.bounds
        
        let orientation = UIApplication.shared.statusBarOrientation
        
        if let videoPreviewLayer = self.videoPreviewLayer {
            switch(orientation) {
            case UIInterfaceOrientation.landscapeLeft:
                videoPreviewLayer.connection?.videoOrientation = AVCaptureVideoOrientation.landscapeLeft
                
            case UIInterfaceOrientation.landscapeRight:
                videoPreviewLayer.connection?.videoOrientation = AVCaptureVideoOrientation.landscapeRight
                
            case UIInterfaceOrientation.portrait:
                videoPreviewLayer.connection?.videoOrientation = AVCaptureVideoOrientation.portrait
                
            case UIInterfaceOrientation.portraitUpsideDown:
                videoPreviewLayer.connection?.videoOrientation = AVCaptureVideoOrientation.portraitUpsideDown
                
            default:
                print("Unknown orientation state")
            }
        }
    }
    
    override func didRotate(from fromInterfaceOrientation: UIInterfaceOrientation) {
        videoPreviewLayer?.frame = self.view.layer.bounds
    }
    
    // MARK: - 动态计算尺寸
    
    // MARK: - 更新导航
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        // 刷新布局
        self.switchTapper.frame = CGRect(origin: .zero, size: kNavboxSize)
        self.switchTapper.alpha = .zero
        self.switchTapper.isHidden = false
        // 等待动画
        UIView.animate(withDuration: 0.58, animations: { [weak self] in
            guard let wkThis = self else { return }
            wkThis.switchTapper.alpha = 1.0
        })
    }

    // MARK: 页面加载前
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        /**刷新布局*/
        guard let kframe = navigationItem.titleView?.frame else { return }
        guard !kframe.size.width.isZero else { return }
        self.kNavboxSize = CGSize(width: kframe.size.width, height: 34)
    }
    
}

extension BYAkScanViewController: AVCaptureVideoDataOutputSampleBufferDelegate {
    
    
    // 获取缓冲图片
    func imageBufferBy(_ buffer: CMSampleBuffer, orientation: UIImage.Orientation) -> UIImage? {
        guard let pixelBuffer = CMSampleBufferGetImageBuffer(buffer) else { return nil }
        let ciImage = CIImage(cvPixelBuffer: pixelBuffer)
        let ciGrect =  CGRect(x: 0, y: 0, width: CVPixelBufferGetWidth(pixelBuffer), height: CVPixelBufferGetHeight(pixelBuffer))
        guard let rspImage = CIContext().createCGImage(ciImage, from: ciGrect) else { return nil }
        return UIImage(cgImage: rspImage, scale: UIScreen.main.scale, orientation: orientation)
    }
    
    // 坐标提取
    static func xx_coordinateBarcode( _ barcode: Barcode, fw: CGFloat, fh: CGFloat) -> CGRect {
        return CGRect(
            x: barcode.frame.origin.x / fw,
            y: barcode.frame.origin.y / fh,
            width: barcode.frame.size.width / fw,
            height: barcode.frame.size.height / fh
        )
    }
    
    
    // 相机采集数据流
    func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
        
        // 无法从示例缓冲区获取图像缓冲区
        guard let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return }

        // 图片方向
        let currentOrientation = imageOrientation(deviceOrientation: UIDevice.current.orientation, cameraPosition: .back)
        // 扫码库识别
        let visionImage = VisionImage(buffer: sampleBuffer)
        visionImage.orientation = currentOrientation
                
        let imageWidth = CGFloat(CVPixelBufferGetWidth(imageBuffer))
        let imageHeight = CGFloat(CVPixelBufferGetHeight(imageBuffer))
        // 重新加载配置
        if self.isReloadConfigValue {
            self.isReloadConfigValue = false
            self.barcodeScanner = BarcodeScanner.barcodeScanner(options: self.barcodeOptions)
        }
        
        barcodeScanner.process(visionImage) { [weak self] features, error in
            guard let wkThis = self else { return  }
     
            guard error == nil, let features = features, !features.isEmpty else { return }
            
            guard !wkThis.isLockValue else { return }
            // 加锁
            wkThis.isLockValue = true
        
            for barcode in features {
                
                // 获取坐标比例
                let normalizedRect = Self.xx_coordinateBarcode(barcode, fw: imageWidth, fh: imageHeight)
                // 坐标转化
                let convertedRect = wkThis.videoPreviewLayer?.layerRectConverted( fromMetadataOutputRect: normalizedRect ) ?? .zero
                // 缓冲图片 - 剪切
                let shearImage = wkThis.imageBufferBy(sampleBuffer, orientation: currentOrientation)?.bb_coordinateTransform(convertedRect )
                // 插入标记
                wkThis.add_site(strValue: barcode.displayValue ?? "", rc: convertedRect, buffer: shearImage)
                // MLKBarcodeFormatCode128
                print("识别[\(features.count)] => \(barcode.format) # \(barcode.valueType) # \(barcode.displayValue ?? "null")")
            }
            
            // 识别一张直接跳转
            wkThis.containerLayer.isHidden = false
            wkThis.reminderLabel.isHidden = false
            wkThis.stopTask()
            
            // 播放音乐
            DispatchQueue.main.async {    BYBundleSubject.playMusic() }
            
            wkThis.completionTrigger?(features.first?.displayValue ?? "")
            DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.382) {
                if features.count == 1 {
                    wkThis.dismiss(animated: true)
                }
            }
            
            // 解锁
            wkThis.isLockValue = true
        }
        
    }
    
    // 计算图片旋转
    private func imageOrientation(
        deviceOrientation: UIDeviceOrientation,
        cameraPosition: AVCaptureDevice.Position
    ) -> UIImage.Orientation {
        switch deviceOrientation {
        case .portrait:
            return cameraPosition == .front ? .leftMirrored : .right
        case .landscapeLeft:
            return cameraPosition == .front ? .downMirrored : .up
        case .portraitUpsideDown:
            return cameraPosition == .front ? .rightMirrored : .left
        case .landscapeRight:
            return cameraPosition == .front ? .upMirrored : .down
        case .faceDown, .faceUp, .unknown:
            return .up
        default:
            return .leftMirrored
        }
    }
    
    // 检查插入数据
    func add_site(strValue: String, rc: CGRect, buffer: UIImage?) -> Void {
        // 检查锚点
        var isNewValue: Bool = true
        for item in outcomeValues where item.codeValue == strValue {
            item.imageBuffer = buffer
            item.imageRect = rc
            isNewValue = false
        }
        
        if isNewValue {
            print("插入新数据=> \(strValue)")
            outcomeValues.append(BYAiScanData(code: strValue, rc: rc, buffer: buffer))
        }
        
        // 刷新布局
        show_site()
    }
    
    // 渲染识别数据
    func show_site() -> Void {
        
        for i in 0 ..< outcomeValues.count {
            let dm = outcomeValues[i]
            if i >= outcomeWidget.count {
                let widget = UIButton(type: .custom)
                widget.layer.borderWidth = 2
                widget.layer.borderColor = markThemeColor.cgColor
                widget.addTarget(self, action: #selector(skipTouch(sender:)), for: .touchUpInside)
                self.view.addSubview(widget)
                outcomeWidget.append(widget)
            }
            outcomeWidget[i].tag = i
            outcomeWidget[i].setImage(bbModularImage("icon_skip_arrow"), for: .normal)
//            outcomeWidget[i].setBackgroundImage(dm.imageBuffer, for: .normal)
            let fw: CGFloat = max(40, dm.imageRect.size.width)
            let fh: CGFloat = max(40, dm.imageRect.size.height)
            outcomeWidget[i].frame = CGRect.init(x: dm.imageRect.origin.x, y: dm.imageRect.origin.y, width: fw, height: fh)
            self.view.bringSubviewToFront(outcomeWidget[i])
        }
    }
    
    @objc func skipTouch(sender: UIButton) {
        print("点击index = > \(sender.tag)")
        
        guard sender.tag < outcomeValues.count else { return }
        
        print("点击数据 => \(outcomeValues[sender.tag].codeValue), \(outcomeValues[sender.tag].imageRect)")
        
        self.completionTrigger?(outcomeValues[sender.tag].codeValue)
        self.dismiss(animated: true)
    }
}

//MARK: - 图片选择代理方法
extension BYAkScanViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
    
    //MARK: -----相册选择图片识别二维码 （条形码没有找到系统方法）
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
        picker.dismiss(animated: true, completion: nil)
        
        let editedImage = info[UIImagePickerController.InfoKey.editedImage] as? UIImage
        let originalImage = info[UIImagePickerController.InfoKey.originalImage] as? UIImage
        guard let image = editedImage ?? originalImage else { return }
        
        // 相册识别
        self.identifyAlbums(pic: image)
    }
    
}
